package io.gitee.mingbaobaba.apijson.querycondition.query.conditions;


import io.gitee.mingbaobaba.apijson.querycondition.query.exception.ConditionException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;

import java.lang.reflect.Field;
import java.text.MessageFormat;
import java.util.*;

/**
 * <p>构建参数基类</p>
 *
 * @author yingsheng.ye
 * @version 1.0.0
 * @since 2023/6/19 18:06
 */
@SuppressWarnings("unchecked")
public abstract class AbstractBaseWrapper<T, R, C extends AbstractBaseWrapper<T, R, C>> {

    private static final List<DslSegment> DSL_SEGMENTS = Arrays.asList(
            new ProjectionSegment(),
            new ConditionSegment(),
            new GroupSegment(),
            new OrderSegment(),
            new ExplainSegment(),
            new AppendSegment()
    );

    protected final C typedThis = (C) this;

    /**
     * 数仓apiJson查询参数
     */
    protected Map<String, Object> apiJsonParams = new HashMap<>();

    /**
     * 条件列表存储
     */
    protected List<Condition> conditionList = new ArrayList<>();

    /**
     * 最后追加到参数列表
     */
    protected Map<String, Object> lastAppendMap = new HashMap<>();

    /**
     * 模式名
     */
    protected String schema;

    /**
     * 表名
     */
    protected String tableName;

    /**
     * 业务标识
     */
    protected String biSigns;

    /**
     * 查询列
     */
    protected Set<String> columnList = new HashSet<>();

    /**
     * 排序列
     */
    protected List<String> orderByList = new ArrayList<>();

    /**
     * 分组列
     */
    protected Set<String> groupList = new HashSet<>();

    /**
     * 分组条件
     */
    protected String havingFunc = null;

    /**
     * 实体类型
     */
    protected Class<T> entityClass;

    /**
     * 执行计划
     */
    protected Boolean explain = false;

    /**
     * 设置join对象
     */
    protected JoinOperation joinOperation;

    /**
     * 分页参数
     */
    protected PageWrapper pageWrapper;

    /**
     * 设置执行计划
     *
     * @param explain 是否开启执行计划
     * @return boolean true为开启 false不开启
     */
    public C setExplain(Boolean explain) {
        this.explain = explain;
        return typedThis;
    }

    /**
     * 设置 schema
     *
     * @param schema 模式
     * @return Children
     */
    public C setSchema(String schema) {
        this.schema = schema;
        return typedThis;
    }

    /**
     * 设置表名
     *
     * @param tableName 表名
     * @return Children
     */
    public C setTableName(String tableName) {
        this.tableName = tableName;
        return typedThis;
    }

    /**
     * 设置表名
     *
     * @param clazz 表名
     * @return Children
     */
    public C setTableName(Class<T> clazz) {
        this.entityClass = clazz;
        return typedThis;
    }

    /**
     * 业务标识
     *
     * @param val 业务标识值
     * @return Children
     */
    public C setBiSigns(String val) {
        this.biSigns = val;
        return typedThis;
    }


    /**
     * 构建查询条件
     *
     * @param clazz 类
     * @return C
     */
    public C select(Class<?> clazz) {
        Field[] fields = getFields(clazz);
        for (Field f : fields) {
            ApiJsonTableField dwTableField = f.getAnnotation(ApiJsonTableField.class);
            String name;
            if (null == dwTableField) {
                name = f.getName();
            } else {
                if (!dwTableField.exist() || StringUtils.isBlank(dwTableField.value())) {
                    continue;
                }
                name = dwTableField.value();
            }
            columnList.add(name);
        }
        return typedThis;
    }

    /**
     * 获取类以及父类所有属性
     *
     * @param clazz Class
     * @return Field[]
     */
    private Field[] getFields(Class<?> clazz) {
        List<Field> fieldList = new ArrayList<>();
        while (clazz != null) {
            fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
            clazz = clazz.getSuperclass();
        }
        Field[] fields = new Field[fieldList.size()];
        fieldList.toArray(fields);
        return fields;
    }


    /**
     * 构建结果
     */
    public void builder() {
        validCondition();
        DSL_SEGMENTS.forEach(segment -> segment.apply(this));
    }

    /**
     * 验证条件
     */
    private void validCondition() {
        //验证join
        if (!(this instanceof JoinOperation) && Objects.nonNull(this.joinOperation)
                && this.joinOperation instanceof JoinWrapper) {
            JoinWrapper<?> joinWrapper = (JoinWrapper<?>) this.joinOperation;
            if (null != joinWrapper.joinOperation) {
                throw new ConditionException("join不允许嵌套使用");
            }
        }
    }

    /**
     * 构建拼接参数
     */
    /**
     * 获取apiJson参数
     *
     * @return Map<String, Object>
     */
    public Map<String, Object> getApiJsonParam() {
        if (apiJsonParams.isEmpty()) {
            this.builder();
        }
        if (this instanceof JoinOperation) {
            return apiJsonParams;
        }
        //重新组装结果
        Map<String, Object> result = new HashMap<>();
        result.put("@schema", this.getSchema());
        Map<String, Object> map = new HashMap<>();
        result.put("[]", map);
        //校验join多层嵌套
        if (Objects.nonNull(this.joinOperation) && this.joinOperation instanceof JoinWrapper) {
            JoinWrapper<?> joinWrapper = (JoinWrapper<?>) this.joinOperation;
            Map<String, Object> joinMap = joinWrapper.getApiJsonParam();
            joinMap.put(joinWrapper.getColumn() + "@",
                    MessageFormat.format("/{0}/{1}", getTable(), joinWrapper.getRelColumn()));
            map.put(joinWrapper.getTable(), joinMap);
        }
        //分页条件
        if (Objects.nonNull(this.pageWrapper)) {
            result.put("total@", "/[]/total");
            //apiJson分页从0开始，页面分页一般是从1开始，所以需要针对分页数进行-1
            apiJsonParams.put("page", this.pageWrapper.getPage() - 1);
            apiJsonParams.put("count", this.pageWrapper.getLimit());
            apiJsonParams.put("query", 2);
        }
        map.put(getTable(), apiJsonParams);
        return result;
    }

    /**
     * 获取模式
     *
     * @return String
     */
    public String getSchema() {
        if (StringUtils.isBlank(schema) && null != entityClass) {
            //判断是否有table注解
            ApiJsonTableName dwTable = entityClass.getAnnotation(ApiJsonTableName.class);
            if (null != dwTable && StringUtils.isNotBlank(dwTable.schema())) {
                //设置Schema
                schema = dwTable.schema();
            }
        }
        Assert.isTrue(StringUtils.isNotBlank(schema), "查询schema不能为空");
        return schema;
    }

    /**
     * 获取表
     *
     * @return String
     */
    public String getTable() {
        if (StringUtils.isBlank(tableName) && null != entityClass) {
            tableName = entityClass.getSimpleName();
            //判断是否有table注解
            ApiJsonTableName dwTable = entityClass.getAnnotation(ApiJsonTableName.class);
            if (null != dwTable && StringUtils.isNotBlank(dwTable.value())) {
                //设置表名
                tableName = dwTable.value();
            }
        }
        Assert.isTrue(StringUtils.isNotBlank(tableName), "查询表名不能为空");
        return tableName;
    }

    /**
     * 获取业务标示
     *
     * @return String
     */
    public String getBiSigns() {
        if (StringUtils.isBlank(biSigns) && null != entityClass) {
            //判断是否有table注解
            ApiJsonTableName dwTable = entityClass.getAnnotation(ApiJsonTableName.class);
            if (null != dwTable && StringUtils.isNotBlank(dwTable.biSigns())) {
                //设置业务标识
                biSigns = dwTable.biSigns();
            }
        }
        Assert.isTrue(StringUtils.isNotBlank(biSigns), "查询业务标识不能为空");
        return biSigns;
    }

    /**
     * 获取对象
     *
     * @return 对象
     */
    public Class<?> getEntityClass() {
        return entityClass;
    }

    /**
     * 获取关联表名
     *
     * @return 关联表名
     */
    public String getJoinTable() {
        return null != joinOperation ? joinOperation.getJoinTable() : null;
    }

}
